package com.example.drainage.ui.multipletype

import android.graphics.Canvas
import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView


/**
 * PackageName : com.ziwenl.meituandemo.ui.store.adapter
 * Author : Ziwen Lan
 * Date : 2020/9/15
 * Time : 13:51
 * Introduction : RecyclerView 悬浮吸顶 Decoration
 * 填充的 decorationLayoutRes 根布局高度需为明确值
 */
class MultipleTypeDecoration(
    /**
     * 被装饰的 RecyclerView
     */
    private val recyclerView: RecyclerView,
    /**
     * 回调接口
     */
    private val mCallbackMultipleType: MultipleTypeDecorationCallback
) : RecyclerView.ItemDecoration() {

    private val viewMap = mutableMapOf<String, MultipleTypeDecorationBean>()

    /**
     * 设置 Item 偏移量
     * 第一个Item:必然留分界空间
     * 其他Item:分组的顶部才预留偏移量空间
     */
    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        val position = parent.getChildAdapterPosition(view)
        if (isShowDecoration(position)) {
            val itemView = getViewByPosition(position).view
            measureLayoutStickyItemView(itemView)
            outRect.top = itemView.measuredHeight
        } else {
            outRect.top = 0
        }
    }

    /**
     * 在 Canvas 上绘制内容，于绘制 item 之后，会覆盖 item
     */
    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
        val itemCount = state.itemCount
        val childCount = parent.childCount
        val left = parent.paddingLeft

        var preDecoration: String
        var currentDecoration = ""
        var view: View
        var position: Int
        var viewBottom: Int
        var itemView: View
        for (i in 0 until childCount) {
            view = parent.getChildAt(i)
            position = parent.getChildAdapterPosition(view)
            preDecoration = currentDecoration
            currentDecoration = mCallbackMultipleType.getDecorationFlag(position)
            if (preDecoration == currentDecoration) {
                continue
            }
            viewBottom = view.bottom
            val decorationBean = getViewByPosition(position)
            itemView = decorationBean.view
            // 分界线的底部Y坐标
            // 如果该View不在顶部,view.top>mDecorationHeight,绘制底部为View.top
            // 如果该View在顶部,但view.top<mDecorationHeight,绘制底部为mDecorationHeight,保证分界线处于界面顶部
            // 如果该View在顶部,view.top<mDecorationHeight,且该View滑动到底部了,且该分组结束,下一组的分界线上来了
            //      此时分界线将被底部分界线顶上去,分界线的底部Y坐标为View.bottom
            var top = itemView.measuredHeight.coerceAtLeast(view.top).toFloat()
            //下一个和当前不一样移动当前
            if (position + 1 < itemCount) {
                val nextDecoration = mCallbackMultipleType.getDecorationFlag(position + 1)
                //组内最后一个view进入了header
                if (nextDecoration != currentDecoration && viewBottom < top) {
                    top = viewBottom.toFloat()
                }
            }
            mCallbackMultipleType.onBindView(decorationBean, position)
            measureLayoutStickyItemView(itemView)
//            if (itemView.height <= 0) {
//                measureLayoutStickyItemView(itemView)
//            }
            if (itemView.measuredHeight <= 0) {
                continue
            }
            val saveCount: Int = c.save()
            c.translate(left.toFloat(), top - itemView.measuredHeight)
            itemView.draw(c)
            c.restoreToCount(saveCount)
        }
    }

    private fun isShowDecoration(position: Int): Boolean {
        return if (position == 0) {
            true
        } else {
            val preDecoration = mCallbackMultipleType.getDecorationFlag(position - 1)
            val currentDecoration = mCallbackMultipleType.getDecorationFlag(position)
            preDecoration != currentDecoration
        }
    }

    private fun getViewByPosition(position: Int): MultipleTypeDecorationBean {
        val flag = mCallbackMultipleType.getDecorationFlag(position)
        var findResult: MultipleTypeDecorationBean? = viewMap[flag]
        if (findResult != null) {
            return findResult
        }
        val type = mCallbackMultipleType.getDecorationViewType(position, flag)
        for (element in viewMap) {
            if (element.value.type == type) {
                findResult = MultipleTypeDecorationBean(flag, type, element.value.view)
                break
            }
        }
        findResult?.let {
            return it
        }
        val view = mCallbackMultipleType.getDecorationViewByType(recyclerView, type)
        return MultipleTypeDecorationBean(flag, type, view).also {
            viewMap[flag] = it
        }
    }

    /**
     * 计算布局吸附的itemView
     *
     */
    private fun measureLayoutStickyItemView(view: View) {
        if (!view.isLayoutRequested) return
        val leftPadding = recyclerView.paddingLeft
        val rightPadding = recyclerView.paddingRight
        val widthSpec = View.MeasureSpec.makeMeasureSpec(
            recyclerView.measuredWidth - leftPadding - rightPadding,
            View.MeasureSpec.EXACTLY
        )
        val heightSpec: Int
        val layoutParams: ViewGroup.LayoutParams = view.layoutParams
        heightSpec = if (layoutParams.height > 0) {
            View.MeasureSpec.makeMeasureSpec(layoutParams.height, View.MeasureSpec.EXACTLY)
        } else {
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        }
        view.measure(widthSpec, heightSpec)
        view.layout(leftPadding, 0, view.measuredWidth, view.measuredHeight)
    }

    class MultipleTypeDecorationBean(val flag: String, val type: Int, val view: View)

    /**
     * 回调接口
     */
    interface MultipleTypeDecorationCallback {
        /**
         * 获得装饰标识位：用来区分不同分组，可以根据实际需求调整为 String(组名) 或者是 Long(组Id) 类型
         */
        fun getDecorationFlag(position: Int): String

        /**
         * 通过位置,以及flag获取该分界线界面的类型
         * 不同的组,可以复用同样的ViewType,方便复用
         */
        fun getDecorationViewType(position: Int, flag: String): Int

        /**
         * 根据类型,获取对应的View
         */
        fun getDecorationViewByType(recyclerView: RecyclerView, type: Int): View

        /**
         * 操作装饰View：填充数据
         */
        fun onBindView(decorationBean: MultipleTypeDecorationBean, position: Int)
    }
}